/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file           : usb_device.c
 * @version        : v2.0_Cube
 * @brief          : This file implements the USB Device
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2025 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/

#include "usb_device.h"
#include "usbd_core.h"
#include "usbd_desc.h"
#include "usbd_msc.h"
#include "usbd_storage_if.h"

/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

/* USER CODE END PV */

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* USB Device Core handle declaration. */
USBD_HandleTypeDef *hUsbDeviceFS;

/*
 * -- Insert your variables declaration here --
 */
/* USER CODE BEGIN 0 */
volatile uint8_t g_device_state = 0; /* USB连接状态 0,没有连接; 1,已经连接 */
/* USER CODE END 0 */

/*
 * -- Insert your external function declaration here --
 */
/* USER CODE BEGIN 1 */

/**
 * @brief       USB接口配置
 *   @note      使能/关闭USB接口, 以便每次启动都可以正常
 *              连接USB
 * @param       state   : 接口状态
 *   @arg       0, 断开USB连接
 *   @arg       1, 使能USB连接
 * @retval      无
 */
void usbd_port_config(uint8_t state)
{
  GPIO_InitTypeDef GPIO_Initure;
  __HAL_RCC_GPIOA_CLK_ENABLE(); /* 使能PORTA时钟 */

  if (state)
  {
    USB->CNTR &= ~(1 << 1); /* PWDN = 0, 退出断电模式 */

    /* PA11/PA12,复用为(USB DM/DP)功 */
    GPIO_Initure.Pin = (GPIO_PIN_11 | GPIO_PIN_12);
    GPIO_Initure.Mode = GPIO_MODE_AF_INPUT;
    GPIO_Initure.Pull = GPIO_PULLUP;
    GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_Initure);
  }
  else
  {
    USB->CNTR |= 1 << 1; /* PWDN = 1, 进入断电模式 */

    /* PA11引脚模式设置,推挽输出 */
    GPIO_Initure.Pin = GPIO_PIN_11;
    GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_Initure.Pull = GPIO_PULLUP;
    GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_Initure);

    /* PA12引脚模式设置,推挽输出 */
    GPIO_Initure.Pin = GPIO_PIN_12;
    HAL_GPIO_Init(GPIOA, &GPIO_Initure);

    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_RESET); /* PA11 = 0 */
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_RESET); /* PA12 = 0 */
  }
}

/**
 * @brief       获取USB状态
 * @param       state   : 0, 获取设备状态; 1, 获取USB状态
 * @note        state=0, 返回值: 0, 未连接; 1, 已连接
 *              state=1, 返回值:  * bit0 : 表示电脑正在向SD卡写入数据
 *                                  bit1 : 表示电脑正从SD卡读出数据
 *                                  bit2 : SD卡写数据错误标志位
 *                                  bit3 : SD卡读数据错误标志位
 *                                  bit4 : 1,表示电脑有轮询操作(表明连接还保持着)
 * @retval      无
 */
uint8_t usb_get_state(uint8_t state)
{
  extern volatile uint8_t g_device_state;
  extern volatile uint8_t g_usb_state_reg;
  if (state == 0)
    return g_device_state;
  else
    return g_usb_state_reg;
}

/**
 * @brief       设置USB状态
 * @param       state   : 0, 设置设备状态; 1, 设置USB状态
 * @param       value   : 状态值
 * @retval      无
 */
void usb_set_state(uint8_t state, uint8_t value)
{
  extern volatile uint8_t g_usb_state_reg;
  extern volatile uint8_t g_device_state;
  if (state == 0)
    g_device_state = value;
  else
    g_usb_state_reg = value;
}

void MX_USB_DEVICE_DeInit(void)
{
  if (hUsbDeviceFS != NULL)
  {
    USBD_DeInit(hUsbDeviceFS);
    USBD_free(hUsbDeviceFS);
    hUsbDeviceFS = NULL;
  }

  extern uint8_t *USBD_StrDesc;
  if (USBD_StrDesc != NULL)
  {
    USBD_free(USBD_StrDesc);
    USBD_StrDesc = NULL;
  }

  extern PCD_HandleTypeDef *hpcd_USB_FS;
  if (hpcd_USB_FS != NULL)
  {
    USBD_free(hpcd_USB_FS);
    hpcd_USB_FS = NULL;
  }
}
/* USER CODE END 1 */

/**
 * Init USB device Library, add supported class and start the library
 * @retval None
 */
void MX_USB_DEVICE_Init(void)
{
  /* USER CODE BEGIN USB_DEVICE_Init_PreTreatment */
  extern uint8_t *USBD_StrDesc;
  extern PCD_HandleTypeDef *hpcd_USB_FS;

  if (hpcd_USB_FS || USBD_StrDesc || hUsbDeviceFS)
  {
    MX_USB_DEVICE_DeInit();
  }

  USBD_StrDesc = (uint8_t *)USBD_malloc(USBD_MAX_STR_DESC_SIZ);
  hpcd_USB_FS = (PCD_HandleTypeDef *)USBD_malloc(sizeof(PCD_HandleTypeDef));
  hUsbDeviceFS = (USBD_HandleTypeDef *)USBD_malloc(sizeof(USBD_HandleTypeDef));

  if (!hpcd_USB_FS || !USBD_StrDesc || !hUsbDeviceFS)
  {
    USBD_DbgLog("USB malloc failed");
    Error_Handler();
  }

  /* USER CODE END USB_DEVICE_Init_PreTreatment */

  /* Init Device Library, add supported class and start the library. */
  if (USBD_Init(hUsbDeviceFS, &FS_Desc, DEVICE_FS) != USBD_OK)
  {
    Error_Handler();
  }
  if (USBD_RegisterClass(hUsbDeviceFS, &USBD_MSC) != USBD_OK)
  {
    Error_Handler();
  }
  if (USBD_MSC_RegisterStorage(hUsbDeviceFS, &USBD_Storage_Interface_fops_FS) != USBD_OK)
  {
    Error_Handler();
  }
  if (USBD_Start(hUsbDeviceFS) != USBD_OK)
  {
    Error_Handler();
  }

  /* USER CODE BEGIN USB_DEVICE_Init_PostTreatment */

  /* USER CODE END USB_DEVICE_Init_PostTreatment */
}

/**
 * @}
 */

/**
 * @}
 */
